package org.atlantis.grosbeak.pot;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.atlantis.grosbeak.lang.Exceptions;
import org.atlantis.grosbeak.pot.transaction.Transaction;
import org.atlantis.grosbeak.pot.transaction.TransactionProvider;

/**
 * 查询操作回调的基类。
 * 
 * @author <a href="mailto:seenoevil.cn@gmail.com">SeeNoEvil</a>
 * 
 * @param <T>
 */
abstract class BaseQueryCallback<T> {

	/**
	 * 执行查询操作。
	 * 
	 * @param txProvider
	 *            事务供应器。
	 * @param sql
	 *            需要执行的查询SQL。
	 * @param params
	 *            查询过程中所需要的参数。
	 * @return 查询后的结果。
	 * @throws PotException
	 */
	public final T execute(TransactionProvider txProvider, String sql,
			Object... params) throws PotException {
		Transaction tx = txProvider.begin();
		Connection con = txProvider.getCurrentConnection();
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			pstmt = con.prepareStatement(sql);
			PotKit.bindParams(pstmt, params);
			rs = pstmt.executeQuery();
			rs.setFetchSize(getFetchSize());
			return ctrlResult(rs);
		} catch (SQLException e) {
			throw Exceptions.wrapThrow(PotException.class, e);
		} finally {
			PotKit.safelyClose(rs);
			PotKit.safelyClose(pstmt);
			tx.commit();
		}
	}

	/**
	 * 获得查询过程中抓取记录的条数。
	 * 
	 * @return 抓取记录的条数。
	 */
	protected abstract int getFetchSize();

	/**
	 * 对查询后得到的ResultSet结果集进行操作，可以转换成自己所需要的对象。
	 * 
	 * @param rs
	 *            ResultSet结果集。
	 * @return 操作后的结果。
	 * @throws SQLException
	 */
	protected abstract T ctrlResult(ResultSet rs) throws SQLException;
}
